// Copyright (C) 2010  Joan Puigcerver Perez, <joapuipe@gmail.com>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
//

#ifndef __DATABASE_HPP__
#define __DATABASE_HPP__

#include <iostream>
#include <fstream>
#include <vector>
#include <list>
#include <cstdlib>
#include <ctime>

#include <Movies.hpp>
#include <People.hpp>
#include <Link.hpp>
#include <Filter.hpp>
#include <LogUtils.hpp>

/**
 * \class Database
 *
 * This class is used to store an in-memory database formed by Persons and Movies. 
 * This database can be seen as a bipartite graph, where an edge between nodes p 
 * and m represents that person p participated in the movie m.
 *
 * Here, the "movie" word refers to a cinema film, a straight-to-video film, 
 * a tv-show, a tv-serie or a video game. Maybe, it would be more appropriated
 * call them "titles" but...
 * 
 * The database (or the graph) is loaded from two different XML files, 
 * take a look at Movies and People classes to see how they are loaded.
 *
 * Apart from loading the database, three actions can be done:
 *   1. Compute the minimum distance and the path between two persons.
 *   2. Compute the list of persons at a distance of N of a given person.
 *   3. Compute the average distance for a given person.
 *
 * \see Movies
 * \see People
 * \see SAXMoviesHandler
 * \see SAXPeopleHandler
 */
class Database {
private:
  Movies movies;
  People people;
  std::vector<Link*> links;
  std::ostream& logfile;
  ost::Mutex&  log_mutex;

  friend class SAXMoviesHandler;
  friend class SAXPeopleHandler;

  /**
   * This function adds a link between a movie and a person.
   * 
   * @param movie The movie.
   * @param person The person.
   * @param work The job of the person in the movie.
   */
  bool add_link(Movie* movie, Person* person, Work work);

  /**
   * A pure Breath First Search algorithm for a bipartite graph (persons and movies).
   * 
   * @param source Initial person
   * @param distances This vector stores the distances between the source and all the other persons.
   * @param max_dist The maximum deep of the search tree.
   * @param filter Filtering options.
   */
  void PureBFS(const Person * source, std::vector<uint32_t>& distances,  const uint32_t max_dist,
	       const Filter filter = Filter()) const;

public:
  /** A pair of pointers to links. */
  typedef std::pair<const Link*, const Link*> LinkPPair;
  /** A list of pair of pointers to links. */
  typedef std::list<LinkPPair> LinkPPairList;
  /** The return type for the Distance request. */
  typedef std::pair<uint32_t,LinkPPairList> DistanceResult;
  /** A list of pointers to persons. */
  typedef std::list<const Person*> PersonPList;

  /** 
   * Constructor.
   *
   * @param logf Output stream used to print log messages.
   * @param logm Mutex to control the access to logf.
   */
  Database(std::ostream& logf = std::cout, ost::Mutex& logm = LOGmutex); 

  /** Destructor. */
  ~Database();

  /** 
   * This function loads the movies and persons from the XML files to the database.
   * If some error is produced, then False is returned. 
   */
  bool load(void);
  
  /**
   * Used to search a person in the database. It receives a name.
   *
   * If the exacte name is found, the first field of the returned pair it's set to true, if not it is set to false.
   * The second field of the returned pair is the list of persons that have a similar name for the given one.
   *
   * @param name Person's name or aka name.
   */
  std::pair< bool, std::list<const Person *> > search_person(const std::string& name) const;
  
  /**
   * This function computes the minimum distance and the path between two persons using a filter.
   * A DistanceResult object is returned.
   * 
   * @param source Initial person.
   * @param target Last person.
   * @param filter Filtering options.
   */
  DistanceResult distance(const Person* source, const Person* target, 
			  const Filter filter = Filter()) const;  
  
  /**
   * This function is used to compute the average number of hops for a given person using some filtering options.
   *
   * @param source Initial person.
   * @param filter Filtering options.
   */
  float center(const Person * source, const Filter filter = Filter()) const;
  
  /**
   * This function is used to obtain a list of persons who are at a distance of N hops from a given one.
   *
   * @param source Initial person.
   * @param dist Distance (number of hops).
   * @param filter Filtering options.
   */
  PersonPList distance_n(const Person * source, const uint32_t dist, 
			 const Filter filter = Filter()) const;

};



#endif
